package de.homelabs.moonrat.page;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import de.homelabs.moonrat.config.MoonratConfigurationManager;
import de.homelabs.moonrat.context.DataProviderService;
import de.homelabs.moonrat.context.IDataProvider;
import de.homelabs.moonrat.context.plugin.content.IContentDataProvider;
import de.homelabs.moonrat.exception.MoonratErrorCode;
import de.homelabs.moonrat.exception.MoonratException;
import de.homelabs.moonrat.metadata.MoonratPageMetaData;
import de.homelabs.moonrat.template.MoonratMenuItem;

@Service
public class MoonratPageManager {
	static Logger logger = Logger.getLogger(MoonratPageManager.class);
	
	static String defaultTemplate = "default.html";
	
	@Autowired
	MoonratConfigurationManager mCfgManager;
	
	@Autowired
	DataProviderService dataProviderService;
	
	public ModelAndView handlePageRequest(HttpServletRequest request,
			HttpServletResponse response, ModelMap map){
		
		boolean homeOnError = true;
		
		//create return model
		Map<String, Object> model = new HashMap<String, Object>();
		SortedMap<Integer, MoonratContentSection> contentSectionMap = new TreeMap<Integer, MoonratContentSection>();
		
		List<IDataProvider> dataProviders = dataProviderService.getDataProviderByProviderKey("content_data_provider");
		
		//search for contenProviders, get content, sort and parse
		try {
			contentSectionMap = getContentSectionMap(dataProviders, request);
		} catch (MoonratException e){
			if (homeOnError && !request.getRequestURI().equalsIgnoreCase("index.html")){
				//back to home
				model.put("infoMessage", MoonratErrorCode.PAGE_NOT_FOUND.getDefaultMessage() + request.getRequestURI());
				return new ModelAndView(new RedirectView(request.getContextPath() + "/index.html"), model);
			} else {
				//exception to contentsection
				MoonratContentSection contentSection = new MoonratContentSection();
				contentSection.setContent(new StringBuffer("<span style='color:red'>A problem getting the content section map for request: "+e.toString()+"</span>"));
				contentSection.setContentOrder(1);
				contentSectionMap.put(1, contentSection);
			}
		}
//		
//		for (IDataProvider dataProvider : dataProviders){
//			if (dataProvider instanceof IContentDataProvider){
//				IContentDataProvider contentDataProvider = (IContentDataProvider) dataProvider;
//				//get content
//				contentSection = new MoonratContentSection();
//				contentSection.setContent(contentDataProvider.getContentByPageUrl(request.getServletPath()));
//				//parse content
//				contentSection = parseContentSection(contentSection);
//				//add to section map
//				for (int i=0; i<contentSectionMap.size();i++){
//					if (!contentSectionMap.containsKey(contentSection.getContentOrder())){
//						contentSectionMap.put(contentSection.getContentOrder(), contentSection);
//						break;
//					} else {
//						//increase order
//						contentSection.setContentOrder(contentSection.getContentOrder()+1);
//					}
//				}
//			}
//		}
		
		//build main content
		StringBuffer content = buildMainContent(contentSectionMap);
		MoonratPageMetaData metaData = getFirstMetaData(contentSectionMap);
		
		if (mCfgManager.isDebug()){
			//add debug info
			content.append(getDebugInfo(request));
		}
		
		//add content
		model.put("content", content);
		
		//add Menu
		List<MoonratMenuItem> mainMenu = new ArrayList<MoonratMenuItem>();
		//menuitem
		MoonratMenuItem mItem = new MoonratMenuItem("index.html", "Home");
		mainMenu.add(mItem);
		mItem = new MoonratMenuItem("test.html", "Test");
		mainMenu.add(mItem);
		model.put("mainmenu", mainMenu);
		
		//title
		model.put("pageTitle", metaData.getPageTitle());
		
		//return default template
		//TODO: how to handle different tamplates
		return new ModelAndView(defaultTemplate, model);
	}
	
	public File getMediaFile(HttpServletRequest request) throws MoonratException{
		List<IDataProvider> dataProviders = dataProviderService.getDataProviderByProviderKey("content_data_provider");

		for (IDataProvider dataProvider : dataProviders){
			if (dataProvider instanceof IContentDataProvider){
				IContentDataProvider contentDataProvider = (IContentDataProvider) dataProvider;
				try {
					//try to find media file with contentDataProvider
					File file = contentDataProvider.getMediaFileByRequest(request);
					//file found
					return file;
				} catch (MoonratException e){
					//try the next one
					continue;
				}
			}
		}
		
		//if we end up here no media file has been found
		throw new MoonratException(MoonratErrorCode.MEDIA_FILE_NOT_FOUND); 
	}
	
	public ModelAndView getDebugPage(HttpServletRequest request, HttpServletResponse response) throws IOException{
		//log
		logger.debug("request received: "+request.getRequestURI());
				
		//content
		StringBuffer content = new StringBuffer();
		content.append("<h1>DebugPage</h1>");
		content.append("<p>request received: "+request.getRequestURI()+"</p>");	
		
		//write back
		response.getWriter().print(getFallbackTemplate(content).toString());
		
		//return null to finish spring handling
		return null;
	}
	
	public StringBuffer getFallbackTemplate(StringBuffer content) {
		try {
			//fallback template resource from classpath
			Resource template = new ClassPathResource(mCfgManager.getConfig().getFallbackTemplate());
			//prepeare buffer
			byte[] templateContent = new byte[(int) template.contentLength()];
			//read complete file to buffer
			template.getInputStream().read(templateContent);
			//Buffer 
			StringBuffer buffer = new StringBuffer();
			
			//parse content if any
			if (content != null && content.length() > 0){
				//content to buffer
				buffer.append(new String(templateContent));
				//find marker
				int markerIndex = buffer.indexOf("${content}");
				//replace with content
				buffer = buffer.replace(markerIndex, markerIndex + 10, content.toString());
			}
			
			//return
			return buffer;
		} catch (IOException e) {
			//create moonratException
			MoonratException me = new MoonratException(MoonratErrorCode.FALLBACK_TEMPLATE_NOT_FOUND, e);
			logger.error(me.toString());
			//throw me;
			return new StringBuffer(me.toString());
		}
	}
	
	private SortedMap<Integer, MoonratContentSection> getContentSectionMap(List<IDataProvider> dataProviders, HttpServletRequest request) throws MoonratException{
		//vars
		MoonratContentSection contentSection;
		SortedMap<Integer, MoonratContentSection> contentSectionMap = new TreeMap<Integer, MoonratContentSection>();
		
		//loop over all contentProviders
		for (IDataProvider dataProvider : dataProviders){
			if (dataProvider instanceof IContentDataProvider){
				IContentDataProvider contentDataProvider = (IContentDataProvider) dataProvider;
				//get content
				contentSection = contentDataProvider.getContentByPageUrl(request);
				//contentSection.setContent(contentDataProvider.getContentByPageUrl(request));
				//parse content
				contentSection = parseContentSection(contentSection);
				//add to section map
				if (contentSectionMap.size() > 0){
					for (int i=0; i<contentSectionMap.size();i++){
						if (!contentSectionMap.containsKey(contentSection.getContentOrder())){
							contentSectionMap.put(contentSection.getContentOrder(), contentSection);
							break;
						} else {
							//increase order
							contentSection.setContentOrder(contentSection.getContentOrder()+1);
						}
					}
				} else {
					//simply add
					contentSectionMap.put(contentSection.getContentOrder(), contentSection);
				}
			}
		}
		
		//return
		return contentSectionMap;
	}
	
	private StringBuffer buildMainContent(SortedMap<Integer, MoonratContentSection> contentSectionMap){
		StringBuffer buffer = new StringBuffer();
		
		for (int key : contentSectionMap.keySet()){
			//content ordered by the SortedMap
			if (contentSectionMap.get(key) != null){
				buffer.append(contentSectionMap.get(key).getContent().toString());
			}
		}
		
		//return
		return buffer;
	}
	
	private MoonratPageMetaData getFirstMetaData(SortedMap<Integer, MoonratContentSection> contentSectionMap){
		//TODO: better strategy
		for (int key : contentSectionMap.keySet()){
			//content ordered by the SortedMap
			if (contentSectionMap.get(key) != null){
				return contentSectionMap.get(key).getMetaData();
			}
		}
		
		//return
		return null;
	}
	
	private MoonratContentSection parseContentSection(MoonratContentSection contentSection){
		contentSection.setContentOrder(1);
		return contentSection;
	}
	
	private StringBuffer getDebugInfo(HttpServletRequest request){
		StringBuffer buffer = new StringBuffer();
		buffer.append("<div style='background-color: #cecece;border: 1px solid #000000;padding: 2px;'>");
		buffer.append("<p>");
		buffer.append("<b>Debug Info (Request Data):</b><br /><br />");
		buffer.append("<b>Request URI</b>: "+request.getRequestURI()+"</br>");
		buffer.append("<b>Context Path</b>: "+request.getContextPath()+"</br>");
		buffer.append("<b>LocalAddress</b>: "+request.getLocalAddr()+"</br>");
		buffer.append("<b>LocalName</b>: "+request.getLocalName()+"</br>");
		buffer.append("<b>LocalPort</b>: "+request.getLocalPort()+"</br>");
		buffer.append("<b>Method</b>: "+request.getMethod()+"</br>");
		buffer.append("<b>PathInfo</b>: "+request.getPathInfo()+"</br>");
		buffer.append("<b>PathTranslated</b>: "+request.getPathTranslated()+"</br>");
		buffer.append("<b>Protocoll</b>: "+request.getProtocol()+"</br>");
		buffer.append("<b>QueryString</b>: "+request.getQueryString()+"</br>");
		buffer.append("<b>RemoteAddress</b>: "+request.getRemoteAddr()+"</br>");
		buffer.append("<b>RemoteHost</b>: "+request.getRemoteHost()+"</br>");
		buffer.append("<b>RemotePort</b>: "+request.getRemotePort()+"</br>");
		buffer.append("<b>RemoteUser</b>: "+request.getRemoteUser()+"</br>");
		buffer.append("<b>RequestURI</b>: "+request.getRequestURI()+"</br>");
		buffer.append("<b>RequestURL</b>: "+request.getRequestURL()+"</br>");
		buffer.append("<b>Schema</b>: "+request.getScheme()+"</br>");
		buffer.append("<b>ServerName</b>: "+request.getServerName()+"</br>");
		buffer.append("<b>ServerPort</b>: "+request.getServerPort()+"</br>");
		buffer.append("<b>ServletPath</b>: "+	request.getServletPath()+"</br>");
		buffer.append("<b>Locale</b>: "+request.getLocale()+"</br>");
		
		//header
		buffer.append("</br>");
		buffer.append("<b>Header Names</b>: <br/>");
		
		@SuppressWarnings("unchecked")
		Enumeration<String> headerNames = request.getHeaderNames(); 
		while (headerNames.hasMoreElements()){
			String header = (String) headerNames.nextElement();
			buffer.append("<b>" + header.toString()+ "</b>: "+request.getHeader(header)+"</br>");
		}
		
		buffer.append("</br>");
		buffer.append("</p>");
		buffer.append("</div>");
		
		//return
		return buffer;
	}
}
